/*
 * TaskProcessing.h
 *
 *  Created on: 2014. 6. 11.
 *      Author: jjaehuny
 */

#ifndef FRAMEWORK_TASKPROCESSING_H_
#define FRAMEWORK_TASKPROCESSING_H_

#include <functional>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <vector>
#include <deque>

#include "../Type.h"

#include "ThreadExecuter.h"

namespace Framework { namespace Util {

class TaskProcessing
{
public:
	typedef std::function<void()> Task;

public:
	TaskProcessing(UINT nThreadExcuterCount)
	{
		clsThreadExecuter_.Run(nThreadExcuterCount, std::bind(& TaskProcessing::DoWork, this));
	}

	~TaskProcessing()
	{
		LOG(INFO) << __PRETTY_FUNCTION__;

		{
			std::lock_guard<std::mutex> lock(mutex_);
			task_deque_.clear();
		}
	}

private:
	TaskProcessing(const TaskProcessing & other) = delete;
	TaskProcessing & operator= (const TaskProcessing & other) = delete;

public:
	void PushTask(Task task)
	{
		{
			std::lock_guard<std::mutex> lock(mutex_);
			task_deque_.push_back(task);
		}
		condition_.notify_one();
	}

	void DoWork()
	{
		LOG(INFO) << "thread id : " << std::this_thread::get_id() << " START";

		while(true)
		{
			Task task = NULL;
			{
				std::unique_lock<std::mutex> lock(mutex_);
				if (true == task_deque_.empty())
				{
					LOG(INFO) << "thread id : " << std::this_thread::get_id() << " WAIT";
					condition_.wait(lock);
				}

				if (true == task_deque_.empty())
					continue;

				task = task_deque_.front();
				task_deque_.pop_front();
			}

			task();
		}
	}

private:
	ThreadExecuter clsThreadExecuter_;
	std::condition_variable condition_;
	std::mutex mutex_;
	std::deque<Task> task_deque_;
};

} /*Util*/ } /*Framework*/

#endif /* FRAMEWORK_TASKPROCESSING_H_ */
